package poker.beans;

import java.util.Collections;
import java.util.Random;
import java.util.Vector;

import org.directwebremoting.ScriptSessions;

import poker.UI;
import poker.beans.PlayerBean.Action;

public class GameBean implements java.io.Serializable {
 	
    private static final int playersAroundTable = 9;
	
	private Vector<PlayerBean> players; 
    private Vector<CardBean> deck;
    private Vector<CardBean> communityCards;
    private int dealer;
    private int activePlayerIndex;
    private int maxBet;
    private int smallBlind;
    private int pot;
    private int playersInGame;
    private int betMultiplier;
    private int timesRaised;
    private int betLimit;
    private boolean winnerDeclared;
    private boolean viewLog;
    private int communityCardIndex;
    private int stage;
    
    public GameBean() {
    }

	public void setPlayers(Vector<PlayerBean> players) {
		this.players = players;
	}

	public Vector<PlayerBean> getPlayers() {
		return players;
	}

	public void setDeck(Vector<CardBean> deck) {
		this.deck = deck;
	}

	public Vector<CardBean> getDeck() {
		return deck;
	}

	public void setCommunityCards(Vector<CardBean> communityCards) {
		this.communityCards = communityCards;
	}

	public Vector<CardBean> getCommunityCards() {
		return communityCards;
	}

	public void setDealer(int dealer) {
		this.dealer = dealer;
	}

	public int getDealer() {
		return dealer;
	}
		
	public void setActivePlayerIndex(int activePlayer) {
		this.activePlayerIndex = activePlayer;
	}

	public int getActivePlayerIndex() {
		return activePlayerIndex;
	}

	public void setMaxBet(int maxBet) {
		this.maxBet = maxBet;
	}

	public int getMaxBet() {
		return maxBet;
	}

	public void setSmallBlind(int smallBlind) {
		this.smallBlind = smallBlind;
	}

	public int getSmallBlind() {
		return smallBlind;
	}

	public void setPot(int pot) {
		this.pot = pot;
	}

	public int getPot() {
		return pot;
	}
	
	public void increasePot(int amount) {
	    this.pot += amount;
	}
	
	public void setPlayersInGame(int playersInGame) {
		this.playersInGame = playersInGame;
	}

	public int getPlayersInGame() {
		return playersInGame;
	}
	
	public void setBetMultiplier(int betMultiplier) {
		this.betMultiplier = betMultiplier;
	}

	public int getBetMultiplier() {
		return betMultiplier;
	}

	public void setTimesRaised(int timesRaised) {
		this.timesRaised = timesRaised;
	}

	public int getTimesRaised() {
		return timesRaised;
	}

	public void setBetLimit(int betLimit) {
		this.betLimit = betLimit;
	}

	public int getBetLimit() {
		return betLimit;
	}

	public void setWinnerDeclared(boolean winnerDeclared) {
		this.winnerDeclared = winnerDeclared;
	}

	public boolean isWinnerDeclared() {
		return winnerDeclared;
	}

	public void setViewLog(boolean viewLog) {
		this.viewLog = viewLog;
	}

	public boolean isViewLog() {
		return viewLog;
	}

	public void setCommunityCardIndex(int comunityCardIndex) {
		this.communityCardIndex = comunityCardIndex;
	}

	public int getCommunityCardIndex() {
		return communityCardIndex;
	}

	public void setStage(int stage) {
		this.stage = stage;
	}

	public int getStage() {
		return stage;
	}
	
	public void incrementDealer(){
		this.dealer++;
	}
	
	public void decrementDealer(){
		this.dealer--;
	}
	
	public void incrementActivePlayer(){
		this.activePlayerIndex++;
	}
	
	public void incrementCommunityCardIndex(){
		this.communityCardIndex++;
	}
	
	public void incrementStage(){
		this.stage++;
	}
	
	public void initGame() {
		players = new Vector<PlayerBean>(9);
		activePlayerIndex = 2;
		betLimit = 2;
		betMultiplier = 1;
		communityCards = new Vector<CardBean>(5);
		communityCardIndex = 0;
		dealer = 0;
		deck = new Vector<CardBean>(52);
		maxBet = 0;
		playersInGame = 9;
		pot = 0;
		smallBlind = 2;
		stage = 0;
		timesRaised = 0;
		viewLog = true;
		winnerDeclared = false;
	}
	
	public void addPlayer(PlayerBean player){
		this.players.add(player);
	}
	
	public PlayerBean getPlayer(int i){
		return this.players.get(i);
	}
	
	public int getDealerId() {
		return players.get( dealer ).getId();
	}

	
	public void resetAll() {
		pot = 0;
		dealer = 0;
		activePlayerIndex = 0;
		betLimit = 0;
		betMultiplier = 0;
		maxBet = 0;
		stage = 0;		
	}
	
	public void shuffleDeck(){
		Collections.shuffle(deck);
	}
	
	public void correctNumOfActivePlayers(){
		try{
			playersInGame = players.size();
		}
		catch(Exception e){
			ScriptSessions.addFunctionCall("alert", "Error at: correctNumOfActivePlayers");
		}
	}
	
	public void increaseBlinds(){
		smallBlind *= 2;
	}

	public void removePlayer(PlayerBean player) {
		players.remove(player);
	}
	
	public void addCommunityCard(){
		communityCards.add(deck.get(0));
	}

	public void correctActivePlayerIndex() {		
		if(activePlayerIndex >= players.size()) activePlayerIndex = 0;
		while(!players.get(activePlayerIndex).isInGame()){
			activePlayerIndex++;
			if(activePlayerIndex >= players.size()) activePlayerIndex = 0;
		}	
	}
	
	public PlayerBean getActivePlayer(){
		try{
			return players.get(activePlayerIndex);
		}
		catch(Exception e){
			ScriptSessions.addFunctionCall("alert", "Error at: getActivePlayer");
		}
		return new PlayerBean();
	}

	public void burn() {
		deck.remove(0);
	}

	public void addCardToPlayer(PlayerBean player) {
		player.addCard(deck.get(0));
		deck.remove(0);
	}	
	
	public void makeDeck(){

		final String[] values = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
		final String[] suits = {"S","H","D","C"};		
		deck = new Vector<CardBean>(52);
	    for (int i = 0; i < suits.length; i++) {
	        for (int j = 0; j < values.length; j++) {
	            CardBean card = new CardBean();
	            card.setNumber(values[j]);
	            card.setSuit(suits[i]);
	            deck.add(card);
	        }
	    }
	}
	
	public void setBlinds(){		
		try{
			int numOfPlayers = players.size();	
			
			int sbi1 = (dealer + 1) %  numOfPlayers;
			int bbi1 = (dealer + 2) %  numOfPlayers;
			int sbi2 = dealer %  numOfPlayers;
			int bbi2 = sbi1;
	
			if ( numOfPlayers > 2 ){		
				players.get(sbi1).increaseBet(smallBlind);
				players.get(bbi1).increaseBet(2 * smallBlind);
							
				activePlayerIndex = (dealer + 3) % players.size();
				
				players.get(sbi1).setAction(Action.SB);
				players.get(bbi1).setAction(Action.BB);
				UI.updatePlayerData(players.get(sbi1));
				UI.updatePlayerData(players.get(bbi1));
							
			}
			else {
				players.get(sbi2).increaseBet(smallBlind);
				players.get(bbi2).increaseBet(2 * smallBlind);
							
				activePlayerIndex = (dealer + 1) % players.size();
				
				players.get(sbi2).setAction(Action.SB);
				players.get(bbi2).setAction(Action.BB);	
				UI.updatePlayerData(players.get(sbi2));
				UI.updatePlayerData(players.get(bbi2));
				
			}
			pot += 3 * smallBlind;
			maxBet += 2 * smallBlind;
		}
		catch (Exception e) {
			ScriptSessions.addFunctionCall("alert", "Error at: setBlinds");
		}
	}

	public void incrementTimesRaised() {
		timesRaised++;
		
	}	

	public void initPlayers() {
		try{	
			for(int i = 0; i < playersAroundTable; i++){
				players.add(new PlayerBean());
				players.get(i).initPlayer(i);			
			}
		}catch(Exception e){
			ScriptSessions.addFunctionCall("alert", "Error at: initPlayers");
		}
	}

	public boolean ready() {
		try{
			for(PlayerBean player : players){
				if(player.getBetSize() < maxBet && player.isInGame()) return false;
			}
		}
		catch(Exception e) {
			ScriptSessions.addFunctionCall("alert", "Error at: ready");
		}
		return allPlayersHaveActed();
	}

	private boolean allPlayersHaveActed(){
		for(PlayerBean player : players){
			if(!player.hasActed() && player.isInGame()) return false;
		}		
		return true;		
	}

	public void dealCards() {
		try{
			for(int i = 0; i < players.size() * 2; i++){
				Thread.sleep(100);
				PlayerBean player = players.get((dealer + i) % players.size());
				addCardToPlayer(player);
				UI.displayCard(player);					
			}	
		}
		catch(Exception e) {
			ScriptSessions.addFunctionCall("alert", "Error at: dealCards");
		}
	}

	public void decrementPlayersInGame() {
		playersInGame--;
	}
		
}